﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Reflection.Emit;
using System.Reflection;

namespace Streamsol.Crm.XrmDevelopmentToolkit
{
    #region Nested type: FastObjectFactory

    internal static class FastObjectFactory
    {
        #region Delegates

        public delegate object CreateObject();

        #endregion

        private static readonly Type coType = typeof(CreateObject);
        private static readonly Hashtable creatorCache = Hashtable.Synchronized(new Hashtable());

        /// <summary>
        /// Create an object that will used as a 'factory' to the specified type T
        /// <returns></returns>
        public static CreateObject CreateObjectFactory(Type t)
        {
            var c = creatorCache[t] as CreateObject;
            if (c == null)
            {
                lock (creatorCache.SyncRoot)
                {
                    c = creatorCache[t] as CreateObject;
                    if (c != null)
                    {
                        return c;
                    }
                    //var info = (from ci in t.GetConstructors()
                    //                       let p = ci.GetParameters()
                    //                       where p.Count() == 1                                          
                    //                       select new {Ctor = ci, ParamType = p.First().ParameterType}).First();

                    var dynMethod = new DynamicMethod("DM$OBJ_FACTORY_" + t.Name, typeof(object), null, t);
                    ILGenerator ilGen = dynMethod.GetILGenerator();

                    ilGen.Emit(OpCodes.Newobj, t.GetConstructor(Type.EmptyTypes));
                    ilGen.Emit(OpCodes.Ret);
                    c = (CreateObject)dynMethod.CreateDelegate(coType);
                    creatorCache.Add(t, c);
                }
            }
            return c;
        }
    }

    #endregion
}
